package cn.sdormitory.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.sdormitory.basedata.dao.BStudentDao;
import cn.sdormitory.basedata.entity.BStudent;
import cn.sdormitory.basedata.vo.BStudentAppHyInfoVo;
import cn.sdormitory.basedata.vo.BStudentAppHyVo;
import cn.sdormitory.basedata.vo.BStudentAppInfoVo;
import cn.sdormitory.basedata.vo.BStudentAppVo;
import cn.sdormitory.common.utils.ContainerUtil;
import cn.sdormitory.common.utils.JwtTokenUtil;
import cn.sdormitory.common.utils.SysUserUtils;
import cn.sdormitory.controller.forms.FilterStudentQueryForm;
import cn.sdormitory.controller.vos.FilterStudentVo;
import cn.sdormitory.leavingSchool.dao.LeavingSchoolCertificateDao;
import cn.sdormitory.leavingSchool.entity.LeavingSchoolCertificate;
import cn.sdormitory.leavingSchool.vo.LeavingSchoolCertificateVO;
import cn.sdormitory.login.BStudentDetails;
import cn.sdormitory.service.AppStudentService;
import cn.sdormitory.sys.service.OnlineUserService;
import cn.sdormitory.sys.vo.LoginInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @创建人：zhouyang
 * @创建时间：2020/12/28 11:08
 * @version：V1.0
 */
@Service
public class AppStudentServiceImpl extends ServiceImpl<BStudentDao, BStudent> implements AppStudentService {

    private Logger log = LoggerFactory.getLogger(AppStudentServiceImpl.class);

    @Resource
    private BStudentDao bStudentDao;

    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private JwtTokenUtil jwtTokenUtil;
    @Resource
    private OnlineUserService onlineUserService;

    @Resource
    private LeavingSchoolCertificateDao schoolCertificateDao;

    @Override
    public Page<FilterStudentVo> getFilterStudentPage(FilterStudentQueryForm form) {
        LambdaQueryWrapper<BStudent> query = form.lambdaQuery();
        Page<BStudent> page = page(form.generatePage(), query);
        List<FilterStudentVo> studentVos = ContainerUtil.mapList(page.getRecords(), item -> BeanUtil.copyProperties(item, FilterStudentVo.class));
        Page<FilterStudentVo> ret = new Page<>(page.getCurrent(),page.getSize(),page.getTotal());
        ret.setRecords(studentVos);
        return ret;
    }

    @Override
    public BStudent getStudentById(int id) {
        return bStudentDao.getStudentById(id);
    }

    @Override
    public boolean updateStuPassword(int id, String oldPassword, String newPassword) {
        String loginPassword = bStudentDao.getStuPassword(id);
        if(null != loginPassword && !"".equals(loginPassword)){
            System.out.println(loginPassword + "student---"+oldPassword);
            if(oldPassword.equals(loginPassword)){
                if(bStudentDao.updateStuPassword(id, newPassword)>0){
                    return true;
                }
                return false;
            }else{
                return false;
            }
        }else{
            return false;
        }
    }

    @Override
    public boolean updateParPassword(int id, String oldPassword, String newPassword) {
        String loginPassword = bStudentDao.getParPassword(id);
        if(null != loginPassword && !"".equals(loginPassword)){
            System.out.println(loginPassword + "parent---"+oldPassword);
            if(oldPassword.equals(loginPassword)){
                if(bStudentDao.updateParPassword(id, newPassword)>0){
                    return true;
                }
                return false;
            }else{
                return false;
            }
        }else{
            return false;
        }
    }

    @Override
    public BStudent getByStudentNo(String studentNo) {
        return bStudentDao.selectOne(new LambdaQueryWrapper<BStudent>().eq(BStudent::getStudentNo,studentNo));
    }

    @Override
    public BStudent getByStuNoAndNameAndClassId(String studentNo, String studentName, Long classId) {
        LambdaQueryWrapper<BStudent> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BStudent::getStudentNo, studentNo);
        wrapper.eq(BStudent::getStudentName, studentName);
        wrapper.eq(BStudent::getClassId, classId);
        return bStudentDao.selectOne(wrapper);
    }

    @Override
    public List<BStudentAppVo> getAppBStudentByDormitoryId(Long dormitoryId,String accessDate) {
        return bStudentDao.getAppBStudentByDormitoryId(dormitoryId,accessDate);
    }

    @Override
    public int getAppBStudentCount(Long dormitoryId, String accessDate) {
        return bStudentDao.getAppBStudentCount(dormitoryId,accessDate);
    }

    @Override
    public List<BStudentAppVo> getAppBStudentByDormitoryIdNo(Long dormitoryId, String accessDate) {
        return bStudentDao.getAppBStudentByDormitoryIdNo(dormitoryId,accessDate);
    }

    @Override
    public int getAppBStudentCountById(String studentNo, String accessDate) {
        return bStudentDao.getAppBStudentCountById(studentNo,accessDate);
    }

    @Override
    public List<BStudentAppInfoVo> getAppStuInfoById(String studentNo, String accessDate) {
        return bStudentDao.getAppStuInfoById(studentNo,accessDate);
    }

    @Override
    public List<BStudentAppInfoVo> getAppStuInfoByIdNo(String studentNo, String accessDate) {
        return bStudentDao.getAppStuInfoByIdNo(studentNo,accessDate);
    }

    @Override
    public int getAppBStuHyCount(Long dormitoryId, String checkDate) {
        return bStudentDao.getAppBStuHyCount(dormitoryId,checkDate);
    }

    @Override
    public List<BStudentAppHyVo> getAppBStuHyByDormitoryId(Long dormitoryId, String checkDate) {
        return bStudentDao.getAppBStuHyByDormitoryId(dormitoryId,checkDate);
    }

    @Override
    public List<BStudentAppHyVo> getAppBStuHyByDormitoryIdNo(Long dormitoryId) {
        return bStudentDao.getAppBStuHyByDormitoryIdNo(dormitoryId);
    }

    @Override
    public int getAppBStuHyCountById(String studentNo, String checkDate) {
        return bStudentDao.getAppBStudentCountById(studentNo,checkDate);
    }

    @Override
    public List<BStudentAppHyInfoVo> getAppStuHyInfoById(String studentNo, String checkDate) {
        return bStudentDao.getAppStuHyInfoById(studentNo,checkDate);
    }

    @Override
    public List<BStudentAppHyInfoVo> getAppStuHyInfoByIdNo(String studentNo) {
        return bStudentDao.getAppStuHyInfoByIdNo(studentNo);
    }

    @Override
    public List<BStudent> getStudentByDormitoryId(Long dormitoryId) {
        return bStudentDao.getStudentByDormitoryId(dormitoryId);
    }

    @Override
    public String login(String loginName, HttpServletRequest request) {
        String token = null;
        //密码需要客户端加密后传递
        try {
            LambdaQueryWrapper<BStudent> studentWrapper = new LambdaQueryWrapper<>();
            studentWrapper.eq(BStudent::getPhone, loginName);
            BStudent bStudent = this.getOne(studentWrapper);

            //查找是否存在当前学生
            if(bStudent ==null) {
                throw new BadCredentialsException("用户不存在");
            }

            if(bStudent.getIsGraduated().equals("1")){
                throw new BadCredentialsException("该学生已经毕业");
            }

            BStudentDetails userDetails = new BStudentDetails(bStudent);

            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);

            token = jwtTokenUtil.generateToken(userDetails.getUsername());

            BStudent studentInfoLogin = SysUserUtils.getStudentUser();
            // 保存在线信息
            onlineUserService.saveAppStudent(studentInfoLogin, token, jwtTokenUtil.getExpiration(), request);

            boolean singleLogin = false;

            if (singleLogin) {
                //踢掉之前已经登录的token
                onlineUserService.checkAppStudentLoginOnUser(studentInfoLogin.getPhone(), token);
            }
        } catch (AuthenticationException e) {
            log.warn("登录异常:{}", e.getMessage());
        }
        return token;
    }

    @Override
    public LoginInfoVo getLoginInfo(String loginName) {
        LambdaQueryWrapper<BStudent> studentWrapper = new LambdaQueryWrapper<>();
        studentWrapper.eq(BStudent::getPhone, loginName);
        BStudent bStudent = this.getOne(studentWrapper);
        LoginInfoVo loginInfoVo = new LoginInfoVo();
        if(bStudent != null){
            loginInfoVo.setLoginId(bStudent.getId());
            loginInfoVo.setLoginName(bStudent.getPhone());
            loginInfoVo.setRoleName("student");
            loginInfoVo.setIdentity(bStudent);
            loginInfoVo.setWxOpenId(bStudent.getWxOpenId());
        }
        return loginInfoVo;
    }

    @Override
    public UserDetails loadStudentInfoByPhone(String phone) {
        LambdaQueryWrapper<BStudent> studentWrapper = new LambdaQueryWrapper<>();
        studentWrapper.eq(BStudent::getPhone, phone);
        BStudent bStudent = this.getOne(studentWrapper);
        if(bStudent == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        BStudentDetails userDetails = new BStudentDetails(bStudent);
        return userDetails;
    }

    @Override
    public int resetPwd(Map<String, String> map) {
        String oldPassWord = map.get("oldPassWord");
        String loginName = map.get("loginName");

        LambdaQueryWrapper<BStudent> studentWrapper = new LambdaQueryWrapper<>();
        studentWrapper.eq(BStudent::getPhone, loginName).eq(BStudent::getIsGraduated,"0");
        BStudent bStudent = this.getOne(studentWrapper);

        if(bStudent == null){
            throw new UsernameNotFoundException("用户不存在");
        }

        boolean matches = passwordEncoder.matches(oldPassWord, bStudent.getStudentPassword());

        if(!matches){
            return -1;
        }

        String newPassWord = map.get("newPassWord");
        String repeatNewPassWord = map.get("repeatNewPassWord");
        if(!newPassWord.equals(repeatNewPassWord)){
            return -2;
        }

        // 新密码
        String newPass = passwordEncoder.encode(newPassWord);
        BStudent stu = new BStudent();
        stu.setStudentPassword(newPass);
        stu.setId(bStudent.getId());
        stu.setModifyTime(new Date());
        return this.baseMapper.updateById(stu);
    }
    
    @Override
    public List<BStudent> getStudentsByStudentNos(List<String> studentNos) {
        return bStudentDao.getStudentInfoByStudentNos(studentNos);
    }
    
    @Override
    public LeavingSchoolCertificateVO getLeavingSchoolCertificate(Long studentId) {
        LeavingSchoolCertificateVO certificateVO = new LeavingSchoolCertificateVO();
        BStudent student = bStudentDao.selectById(studentId);
        certificateVO.setStudentName(student.getStudentName());
        certificateVO.setClassName(student.getClassName());
        certificateVO.setDormitoryNo(student.getDormitoryNo());
        certificateVO.setStuPhoto(student.getStuPhoto());
        certificateVO.setStatus(false);

        LambdaQueryWrapper<LeavingSchoolCertificate> certificateWrapper = new LambdaQueryWrapper<>();
        certificateWrapper.eq(LeavingSchoolCertificate::getStudentId,studentId);
        certificateWrapper.apply("DATE(leave_date) = CURDATE()");
        LeavingSchoolCertificate certificate = schoolCertificateDao.selectOne(certificateWrapper);
        if(Optional.ofNullable(certificate).isPresent()) {
            certificateVO.setStatus(true);
        }

        return certificateVO;
    }

}
